///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//#include "Core/Commons.h"
#include "PhysicalWorld.h"
//#include "CColladaDatabase.h"
#include "FpsColladaDatabase.h"
#include "Commons.h"
#include "Utils\Utils.h"
#include "IMesh.h"
//#include "IMeshSceneNode.h"
//#include "CColladaMeshSceneNode.h"
#include <float.h>

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

using namespace irr;
using namespace core;
using namespace scene;
//using namespace collada;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define AVR_ROOMS_PER_LEVEL						(1)
#define AVR_PLACEHOLDERS_TRIANGLES_PER_ROOM		(12 * 5)

#define AVR_TRIANGLES_PER_TEST					(512)
#define DOOR_TRIANGLES_PER_ROOM					(12 * 2)

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CPhysicalRoom::CPhysicalRoom()
{
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CPhysicalRoom::~CPhysicalRoom()
{
	m_triangles.clear();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CPhysicalRoom::ReallocateTriangleList(int size)
{
	m_triangles.reallocate(size);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int CPhysicalRoom::AddTriangle(const irr::core::triangle3df& triangle)
{
	m_triangles.push_back(triangle);

	return m_triangles.size() - 1;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CPhysicalWorld::CPhysicalWorld()
{
	m_triangles.reallocate(AVR_TRIANGLES_PER_TEST);

	//m_rooms.reallocate(AVR_ROOMS_PER_LEVEL);

	// add general room
	//m_rooms.push_back(new CPhysicalRoom());
	m_room = new CPhysicalRoom();

	//ActivateCollisionRoom(0, true);
	//m_noRooms = 1;

#ifdef _DEBUG
	//strcpy(m_rooms[0]->m_roomName, "GLOBAL");
#endif //_DEBUG

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CPhysicalWorld::~CPhysicalWorld()
{
	m_triangles.clear();

	//for(int i = 0; i < m_rooms.size(); i++)
	//{
	//	CPhysicalRoom* pRoom = m_rooms[i];
	//	delete pRoom;		
	//}
	//m_rooms.clear();
	delete m_room;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int CPhysicalWorld::AddCollisionRoom(const char* meshName, const matrix4& transformMat)
{
//	//m_rooms.push_back(new CPhysicalRoom());
//	//m_noRooms = m_rooms.size();
//
//	CPhysicalRoom* pRoom = m_room;
//
//	// no mesh -> is a door, triangles will be added later
//	if(meshName == 0)
//	{
//		//pRoom->ReallocateTriangleList(DOOR_TRIANGLES_PER_ROOM);
//		return  1;
//	}
//
//	ISceneNode*		node		=	ConstructColladaScene(meshName);
//	if( node == NULL )
//	{
//		return 99;
//	}
//
//	array<CColladaMeshSceneNode*> meshesNodes;
//	GetColladaMeshesListFromVisualScene(node, &meshesNodes);
//
//	u32 totalFaceCount = 0;
//	for (int i = meshesNodes.size() - 1; i >= 0; i--)
//	{
//		IMesh* mesh = meshesNodes[i]->getMesh();
//		
//		const u32 cnt = mesh->getMeshBufferCount();
//		for (u32 j = 0; j < cnt; j++)
//		{
//			totalFaceCount += mesh->getMeshBuffer(j)->getIndexCount();
//		}
//	}
//	totalFaceCount /= 3;
//	totalFaceCount += AVR_PLACEHOLDERS_TRIANGLES_PER_ROOM;
//
//	//pRoom->ReallocateTriangleList(totalFaceCount);
//
//	for (int i = meshesNodes.size() - 1; i >= 0; i--)
//	{
//		IMeshSceneNode*	meshNode	=	meshesNodes[i];
//		IMesh*			mesh		=	meshNode->getMesh();
//		const matrix4&	mat			=	meshNode->getAbsoluteTransformation();
//		const u32 cnt = mesh->getMeshBufferCount();
//		for (u32 i = 0; i < cnt; i++)
//		{
//			const IMeshBuffer*	buf		=	mesh->getMeshBuffer(i);
//			const u32			idxCnt	=	buf->getIndexCount();
//			const u16* const	indices	=	buf->getIndices();
//
//			GX_ASSERT(buf->getVertexType() == video::EVT_COMPONENT_ARRAYS);
//
//			video::S3DVertexComponentArrays *pVertices = (video::S3DVertexComponentArrays *)buf->getVertices();
//			video::S3DVertexComponentArrays::SAccessorEx<core::vector3d, float> accessor;
//
//			if (pVertices->getPositionAccessor(accessor))
//			{
//				return 2;
//			}
//		
//			for (u32 j = 0; j < idxCnt; j += 3)
//			{
//		
//	#ifndef _IRR_USE_RIGHT_HAND_CONVENTION_
//				triangle3df tri(accessor[indices[j + 0]],
//								  accessor[indices[j + 1]],
//								  accessor[indices[j + 2]]);
//	#else
//				triangle3df tri(accessor[indices[j + 2]],
//								  accessor[indices[j + 1]],
//								  accessor[indices[j + 0]]);
//	#endif //_IRR_USE_RIGHT_HAND_CONVENTION_
//
//				mat.transformVect(tri.pointA);
//				mat.transformVect(tri.pointB);
//				mat.transformVect(tri.pointC);
//
//				transformMat.transformVect(tri.pointA);
//				transformMat.transformVect(tri.pointB);
//				transformMat.transformVect(tri.pointC);
//
//				pRoom->AddTriangle(tri);
//			}
//		}
//	}
//
//#ifdef _DEBUG
//	strcpy(pRoom->m_roomName, meshName);
//	DEBUG_OUT("<CD> ROOM \"%s\" has %d collision triangles\n", pRoom->m_roomName, pRoom->GetTrianglesCount());
//#endif //_DEBUG
//
//	node->drop();

	return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int CPhysicalWorld::AddCollisionTriangleInRoom(int roomIndex, const triangle3df& triangle)
{
	CPhysicalRoom* pRoom = m_room;

	pRoom->AddTriangle(triangle);

#ifdef _DEBUG
	DEBUG_OUT("<CD> UPDATE ROOM \"%s\" has %d collision triangles\n", pRoom->m_roomName, pRoom->GetTrianglesCount());
#endif //_DEBUG

	return pRoom->GetTrianglesCount() - 1;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CPhysicalWorld::TransformCollisionTriangles(const vector3df& invRadius)
{
	m_triangles.set_used(0);

	//for(int i = 0; i < m_noRooms; i++)
	{
		CPhysicalRoom* pRoom = m_room;

		//if(!pRoom->IsActive())
		//{
		//	continue;
		//}

		const array<triangle3df>& triangles		=	pRoom->GetTriangles();

		for(u32 j = 0; j < triangles.size(); j++)
		{
			m_triangles.push_back(triangles[j]);

			triangle3df& triangle = m_triangles.getLast();

			triangle.pointA *= invRadius;
			triangle.pointB *= invRadius;
			triangle.pointC *= invRadius;
		}
	}

	DEBUG_OUT("<CD> - %d triangles transformed\n", m_triangles.size());
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

inline bool CPhysicalWorld::GetLowestRoot(f32 a, f32 b, f32 c, f32 maxR, f32* root)
{
	// check if solution exists
	f32 determinant = b*b - 4.0f*a*c;

	// if determinant is negative, no solution
	if (determinant < 0.0f) return false;

	// calculate two roots: (if det==0 then x1==x2
	// but lets disregard that slight optimization)
	// burningwater: sqrt( 0) is an illegal operation.... smth should be done...

	f32 sqrtD = (f32)sqrt(determinant);

	f32 r1 = (-b - sqrtD) / (2*a);
	f32 r2 = (-b + sqrtD) / (2*a);

	// sort so x1 <= x2
	if (r1 > r2) { f32 tmp=r2; r2=r1; r1=tmp; }

	// get lowest root
	if (r1 > 0 && r1 < maxR)
	{
		*root = r1;
		return true;
	}

	// its possible that we want x2, this can happen if x1 < 0
	if (r2 > 0 && r2 < maxR)
	{
		*root = r2;
		return true;
	}

	return false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CPhysicalWorld::CollideWithTriangles()
{
	const u32 noTriangles = m_triangles.size();

	for(u32 i = 0; i < noTriangles; i++)
	{
		const triangle3df& triangle = m_triangles[i];

		const core::plane3d<f32> trianglePlane = triangle.getPlane();

		// only check front facing polygons
		if (!trianglePlane.isFrontFacing(m_colESpaceNormalizedVelocity))
			continue;

		// get interval of plane intersection

		f32 t1, t0;
		bool embeddedInPlane = false;

		// calculate signed distance from sphere position to triangle plane
		f32 signedDistToTrianglePlane = trianglePlane.getDistanceTo(
			m_colESpaceBasePoint);

		f32 normalDotVelocity =
			trianglePlane.Normal.dotProduct(m_colESpaceVelocity);

		if ( core::iszero ( normalDotVelocity ) )
		{
			// sphere is traveling parallel to plane

			if (fabs(signedDistToTrianglePlane) >= 1.0f)
				continue; // no collision possible
			else
			{
				// sphere is embedded in plane
				embeddedInPlane = true;
				t0 = 0.0;
				t1 = 1.0;
			}
		}
		else
		{
			normalDotVelocity = core::reciprocal ( normalDotVelocity );

			// N.D is not 0. Calculate intersection interval
			t0 = (-1.f - signedDistToTrianglePlane) * normalDotVelocity;
			t1 = (1.f - signedDistToTrianglePlane) * normalDotVelocity;

			// Swap so t0 < t1
			if (t0 > t1) { f32 tmp = t1; t1 = t0; t0 = tmp;	}

			// check if at least one value is within the range
			if (t0 > 1.0f || t1 < 0.0f)
				continue; // both t values are outside 1 and 0, no collision possible

			// clamp to 0 and 1
			t0 = core::clamp ( t0, 0.f, 1.f );
			t1 = core::clamp ( t1, 0.f, 1.f );
		}

		// at this point we have t0 and t1, if there is any intersection, it
		// is between this interval
		core::vector3df collisionPoint;
		bool foundCollision = false;
		f32 t = 1.0f;

		// first check the easy case: Collision within the triangle;
		// if this happens, it must be at t0 and this is when the sphere
		// rests on the front side of the triangle plane. This can only happen
		// if the sphere is not embedded in the triangle plane.

		if (!embeddedInPlane)
		{
			core::vector3df planeIntersectionPoint =
				(m_colESpaceBasePoint - trianglePlane.Normal)
				+ (m_colESpaceVelocity * t0);

			if (triangle.isPointInsideFast(planeIntersectionPoint))
			{
				foundCollision = true;
				t = t0;
				collisionPoint = planeIntersectionPoint;
			}
		}

		// if we havent found a collision already we will have to sweep
		// the sphere against points and edges of the triangle. Note: A
		// collision inside the triangle will always happen before a
		// vertex or edge collision.

		if (!foundCollision)
		{
			core::vector3df velocity = m_colESpaceVelocity;
			core::vector3df base = m_colESpaceBasePoint;

			f32 velocitySqaredLength = velocity.getLengthSQ();
			f32 a,b,c;
			f32 newT;

			// for each edge or vertex a quadratic equation has to be solved:
			// a*t^2 + b*t + c = 0. We calculate a,b, and c for each test.

			// check against points
			a = velocitySqaredLength;

			// p1
			b = 2.0f * (velocity.dotProduct(base - triangle.pointA));
			c = (triangle.pointA-base).getLengthSQ() - 1.f;
			if (GetLowestRoot(a,b,c,t, &newT))
			{
				t = newT;
				foundCollision = true;
				collisionPoint = triangle.pointA;
			}

			// p2
			if (!foundCollision)
			{
				b = 2.0f * (velocity.dotProduct(base - triangle.pointB));
				c = (triangle.pointB-base).getLengthSQ() - 1.f;
				if (GetLowestRoot(a,b,c,t, &newT))
				{
					t = newT;
					foundCollision = true;
					collisionPoint = triangle.pointB;
				}
			}

			// p3
			if (!foundCollision)
			{
				b = 2.0f * (velocity.dotProduct(base - triangle.pointC));
				c = (triangle.pointC-base).getLengthSQ() - 1.f;
				if (GetLowestRoot(a,b,c,t, &newT))
				{
					t = newT;
					foundCollision = true;
					collisionPoint = triangle.pointC;
				}
			}

			// check against edges:

			// p1 --- p2
			core::vector3df edge = triangle.pointB - triangle.pointA;
			core::vector3df baseToVertex = triangle.pointA - base;
			f32 edgeSqaredLength = edge.getLengthSQ();
			f32 edgeDotVelocity = edge.dotProduct(velocity);
			f32 edgeDotBaseToVertex = edge.dotProduct(baseToVertex);

			// calculate parameters for equation
			a = edgeSqaredLength* -velocitySqaredLength +
				edgeDotVelocity*edgeDotVelocity;
			b = edgeSqaredLength* (2.f *velocity.dotProduct(baseToVertex)) -
				2.0f*edgeDotVelocity*edgeDotBaseToVertex;
			c = edgeSqaredLength* (1.f -baseToVertex.getLengthSQ()) +
				edgeDotBaseToVertex*edgeDotBaseToVertex;

			// does the swept sphere collide against infinite edge?
			if (GetLowestRoot(a,b,c,t,&newT))
			{
				f32 f = (edgeDotVelocity*newT - edgeDotBaseToVertex) / edgeSqaredLength;
				if (f >=0.0f && f <= 1.0f)
				{
					// intersection took place within segment
					t = newT;
					foundCollision = true;
					collisionPoint = triangle.pointA + (edge*f);
				}
			}

			// p2 --- p3
			edge = triangle.pointC-triangle.pointB;
			baseToVertex = triangle.pointB - base;
			edgeSqaredLength = edge.getLengthSQ();
			edgeDotVelocity = edge.dotProduct(velocity);
			edgeDotBaseToVertex = edge.dotProduct(baseToVertex);

			// calculate parameters for equation
			a = edgeSqaredLength* -velocitySqaredLength +
				edgeDotVelocity*edgeDotVelocity;
			b = edgeSqaredLength* (2*velocity.dotProduct(baseToVertex)) -
				2.0f*edgeDotVelocity*edgeDotBaseToVertex;
			c = edgeSqaredLength* (1-baseToVertex.getLengthSQ()) +
				edgeDotBaseToVertex*edgeDotBaseToVertex;

			// does the swept sphere collide against infinite edge?
			if (GetLowestRoot(a,b,c,t,&newT))
			{
				f32 f = (edgeDotVelocity*newT-edgeDotBaseToVertex) /
					edgeSqaredLength;
				if (f >=0.0f && f <= 1.0f)
				{
					// intersection took place within segment
					t = newT;
					foundCollision = true;
					collisionPoint = triangle.pointB + (edge*f);
				}
			}


			// p3 --- p1
			edge = triangle.pointA-triangle.pointC;
			baseToVertex = triangle.pointC - base;
			edgeSqaredLength = edge.getLengthSQ();
			edgeDotVelocity = edge.dotProduct(velocity);
			edgeDotBaseToVertex = edge.dotProduct(baseToVertex);

			// calculate parameters for equation
			a = edgeSqaredLength* -velocitySqaredLength +
				edgeDotVelocity*edgeDotVelocity;
			b = edgeSqaredLength* (2*velocity.dotProduct(baseToVertex)) -
				2.0f*edgeDotVelocity*edgeDotBaseToVertex;
			c = edgeSqaredLength* (1-baseToVertex.getLengthSQ()) +
				edgeDotBaseToVertex*edgeDotBaseToVertex;

			// does the swept sphere collide against infinite edge?
			if (GetLowestRoot(a,b,c,t,&newT))
			{
				f32 f = (edgeDotVelocity*newT-edgeDotBaseToVertex) /
					edgeSqaredLength;
				if (f >=0.0f && f <= 1.0f)
				{
					// intersection took place within segment
					t = newT;
					foundCollision = true;
					collisionPoint = triangle.pointC + (edge*f);
				}
			}
		}// end no collision found

		// set result:
		if (foundCollision)
		{
			// distance to collision is t
			f32 distToCollision = t*m_colESpaceVelocity.getLength();

			// does this triangle qualify for closest hit?
			if (!m_colCollisionFound ||
				distToCollision	< m_colNearestDistance)
			{
				m_colNearestDistance = distToCollision;
				m_colESpaceIntersectionPoint = collisionPoint;
				m_colCollisionFound = true;
				//colData->intersectionTriangle = triangle;
				m_colTriangleHits++;
			}

		}// end found collision
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CPhysicalWorld::CollideWithWorld(int step)
{
	const f32 veryCloseDistance = 0.005f;


	if(step >= 5)
	{
		m_colESpaceResultPosition = m_colESpaceStartPosition;
		return;
	}

	CollideWithTriangles();

	if(!m_colCollisionFound)
	{
		m_colESpaceResultPosition = m_colESpaceStartPosition + m_colESpaceVelocity;
		return;
	}

	// original destination point
	core::vector3df destinationPoint	=	m_colESpaceStartPosition + m_colESpaceVelocity;
	core::vector3df newBasePoint		=	m_colESpaceStartPosition;

	// only update if we are not already very close
	// and if so only move very close to intersection, not to the
	// exact point
	if (m_colNearestDistance >= veryCloseDistance)
	{
		core::vector3df v = m_colESpaceVelocity;
		v.setLength( m_colNearestDistance - veryCloseDistance );
		newBasePoint = m_colESpaceBasePoint + v;

		v.normalize();
		m_colESpaceIntersectionPoint -= (v * veryCloseDistance);
	}

	// calculate sliding plane

	core::vector3df slidePlaneOrigin = m_colESpaceIntersectionPoint;
	core::vector3df slidePlaneNormal = newBasePoint - m_colESpaceIntersectionPoint;
	slidePlaneNormal.normalize();
	core::plane3d<f32> slidingPlane(slidePlaneOrigin, slidePlaneNormal);

	core::vector3df newDestinationPoint =
		destinationPoint -
		(slidePlaneNormal * slidingPlane.getDistanceTo(destinationPoint));

	// generate slide vector

	core::vector3df newVelocityVector = newDestinationPoint -
		m_colESpaceIntersectionPoint;

	if (newVelocityVector.getLength() < veryCloseDistance)
	{
		m_colESpaceResultPosition	=	newBasePoint;
	}

	{
		m_colESpaceStartPosition		=	newBasePoint;
		m_colESpaceVelocity				=	newVelocityVector;
		m_colESpaceNormalizedVelocity	=	m_colESpaceVelocity;
		m_colESpaceNormalizedVelocity.normalize();
		m_colESpaceBasePoint			=	m_colESpaceStartPosition;
		m_colCollisionFound				=	false;
		m_colNearestDistance			=	FLT_MAX;


		CollideWithWorld(step + 1);
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool CPhysicalWorld::CollideEllipsoidWithWorld(const vector3df&		initpos,
												const vector3df&	finalpos, 
												const vector3df&	radius, 
												vector3df&			newpos,
												bool&				bFalling)
{
	const vector3df gravity(0.f,0.f,-10.f);
	const float SlidingSpeed =  0.005f;

	GX_ASSERT(radius.X != 0 && radius.Y != 0 && radius.Z != 0);
	const vector3df invRadius(1.f / radius.X, 1.f / radius.Y, 1.f / radius.Z);



	vector3df colStartPosition	=	initpos;
	vector3df colVelocity		=	finalpos - initpos;

	// position in center of ellipsoid
	colStartPosition.Z += radius.Z;

	// scale the world, so our ellipsoid will become a sphere
	// if radius is constant, we could precalculate these transformations
	{
		TransformCollisionTriangles(invRadius);
	}

	// movement test
	{
		m_colCollisionFound				=	false;
		m_colNearestDistance			=	FLT_MAX;
		m_colESpaceStartPosition		=	colStartPosition	*	invRadius;
		m_colESpaceVelocity				=	colVelocity			*	invRadius;
		m_colESpaceNormalizedVelocity	=	m_colESpaceVelocity;
		m_colESpaceNormalizedVelocity.normalize();
		m_colESpaceBasePoint			=	m_colESpaceStartPosition;


		CollideWithWorld(0);
	}

	m_colTriangleHits	=	0;

	// gravity test
	if(gravity.X != 0.f || gravity.Y != 0.f || gravity.Z != 0.f)
	{
		m_colCollisionFound				=	false;
		m_colNearestDistance			=	FLT_MAX;
		m_colESpaceStartPosition		=	m_colESpaceResultPosition;
		m_colESpaceVelocity				=	gravity		*	invRadius;
		m_colESpaceNormalizedVelocity	=	m_colESpaceVelocity;
		m_colESpaceNormalizedVelocity.normalize();
		m_colESpaceBasePoint			=	m_colESpaceStartPosition;

		CollideWithWorld(0);
	}


	newpos = m_colESpaceResultPosition * radius;
	newpos.Z -= radius.Z;

	bFalling	=	(m_colTriangleHits == 0);

	//newpos = finalpos;

	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool CPhysicalWorld::CollideRayWithWorld(const vector3df& from, 
											const vector3df& to, 
											vector3df& outIntersectionPoint, 
											triangle3df& outIntersectionTriangle)
{
	bool bCollisionFound	=	false;

	float minX = core::min_(from.X, to.X);
	float maxX = core::max_(from.X, to.X);
	float minY = core::min_(from.Y, to.Y);
	float maxY = core::max_(from.Y, to.Y);
	float minZ = core::min_(from.Z, to.Z);
	float maxZ = core::max_(from.Z, to.Z);


	const vector3df linevect	=	(to - from).normalize();
	float rayLengthSQ			=	(to - from).getLengthSQ();
	float minDistanceSQ			=	FLT_MAX;
	vector3df intersectionPoint;

	outIntersectionPoint = to;

	//for(int i = 0; i < m_noRooms; i++)
	{
		CPhysicalRoom* pRoom = m_room;

		//if(!pRoom->IsActive())
		//{
		//	continue;
		//}

		const array<triangle3df>& triangles		=	pRoom->GetTriangles();

		for(u32 j = 0; j < triangles.size(); j++)
		{
			const triangle3df& triangle = triangles[j];

			if(minX > triangle.pointA.X && minX > triangle.pointB.X && minX > triangle.pointC.X)
				continue;

			if(maxX < triangle.pointA.X && maxX < triangle.pointB.X && maxX < triangle.pointC.X)
				continue;

			if(minY > triangle.pointA.Y && minY > triangle.pointB.Y && minY > triangle.pointC.Y)
				continue;

			if(maxY < triangle.pointA.Y && maxY < triangle.pointB.Y && maxY < triangle.pointC.Y)
				continue;

			if(minZ > triangle.pointA.Z && minZ > triangle.pointB.Z && minZ > triangle.pointC.Z)
				continue;

			if(maxZ < triangle.pointA.Z && maxZ < triangle.pointB.Z && maxZ < triangle.pointC.Z)
				continue;

			if (!triangle.isFrontFacing(linevect))
				continue;

			if (triangle.getIntersectionWithLine(from, linevect, intersectionPoint))
			{
				const float	tmp		=	intersectionPoint.getDistanceFromSQ(from);
				const float	tmp2	=	intersectionPoint.getDistanceFromSQ(outIntersectionPoint);

				if (tmp < rayLengthSQ && tmp2 < rayLengthSQ && tmp < minDistanceSQ)
				{
					minDistanceSQ			=	tmp;
					bCollisionFound			=	true;

					outIntersectionPoint	=	intersectionPoint;
					outIntersectionTriangle	=	triangle;

					minX = core::min_(from.X, intersectionPoint.X);
					maxX = core::max_(from.X, intersectionPoint.X);
					minY = core::min_(from.Y, intersectionPoint.Y);
					maxY = core::max_(from.Y, intersectionPoint.Y);
					minZ = core::min_(from.Z, intersectionPoint.Z);
					maxZ = core::max_(from.Z, intersectionPoint.Z);
				}
			}			
		}
	}

	return bCollisionFound;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
